home *** CD-ROM | disk | FTP | other *** search
/ FM Towns: Free Software Collection 9 / FM Towns Free Software Collection 9.iso / t_os / tool / helper / src / midi.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-16  |  6.1 KB  |  305 lines

  1. #include    <stdio.h>
  2. #include    <stdlib.h>
  3.  
  4. #define    TRUE    1
  5. #define    FALSE    0
  6. #define    ERR    (-1)
  7.  
  8. static    unsigned long    midi_clock = 0;
  9.  
  10. static    unsigned long    getdword(char *p)
  11. {
  12.     unsigned long l;
  13.  
  14.     l  = (unsigned char)(*(p++)); l <<= 8;
  15.     l |= (unsigned char)(*(p++)); l <<= 8;
  16.     l |= (unsigned char)(*(p++)); l <<= 8;
  17.     l |= (unsigned char)(*(p++));
  18.     return l;
  19. }
  20. static    unsigned long    get3byte(char *p)
  21. {
  22.     unsigned long l;
  23.  
  24.     l  = (unsigned char)(*(p++)); l <<= 8;
  25.     l |= (unsigned char)(*(p++)); l <<= 8;
  26.     l |= (unsigned char)(*(p++));
  27.     return l;
  28. }
  29. static    int    getword(char *p)
  30. {
  31.     int i;
  32.  
  33.     i  = (unsigned char)(*(p++)); i <<= 8;
  34.     i |= (unsigned char)(*(p++));
  35.     return i;
  36. }
  37. static    int    getdelta(char *p, unsigned long *delta)
  38. {
  39.     int n = 0;
  40.  
  41.     *delta = 0;
  42.     while ( (p[n] & 0x80) != 0 ) {
  43.     *delta |= (p[n++] & 0x7F);
  44.     *delta = (*delta << 7);
  45.     }
  46.     *delta |= p[n++];
  47.     return n;
  48. }
  49. static    void    MIDI_clock_count()
  50. {
  51.     midi_clock++;
  52. }
  53. int    PLAY_midi(char *file)
  54. {
  55.     int n, i;
  56.     int sw,x,y;
  57.     FILE *fp;
  58.     unsigned long file_size;
  59.     unsigned long size;
  60.     unsigned long delta;
  61.     unsigned long clk;
  62.     char *top, *ptr, *btm;
  63.     int format, ntrks, division;
  64.     int port, track, tempo, st;
  65.     struct {
  66.     char        *ptr;
  67.     char        *btm;
  68.     char        cmd;
  69.     unsigned long    clk;
  70.     } trtab[32];
  71.     char tmp[4];
  72.     char note[16][128];
  73.     int dsp = 0;
  74.  
  75.     DSP_mos(2);
  76.     if( (fp = fopen(file, "rb")) == NULL ) {
  77.     DSP_mos(0);
  78.     kakunin("MIDIファイルのオープンに失敗しました");
  79.     return ERR;
  80.     }
  81.  
  82.     fseek(fp, 0L, SEEK_END);
  83.     file_size = ftell(fp);
  84.     rewind(fp);
  85.  
  86.     if( (top = (char *)malloc((int)file_size)) == NULL ) {
  87.     DSP_mos(0);
  88.     fclose(fp);
  89.     kakunin("メモリが足りませんでした");
  90.     return ERR;
  91.     }
  92.  
  93.     if ( fread(top, (int)file_size, 1, fp) != 1 ) {
  94.     DSP_mos(0);
  95.     kakunin("MIDIファイルの読み込みに失敗しました");
  96.     return ERR;
  97.     }
  98.     fclose(fp);
  99.     DSP_mos(0);
  100.  
  101.     ptr = top;
  102.     btm = top + file_size;
  103.  
  104.     if ( strncmp(ptr, "MThd", 4) != 0 &&
  105.      file_size > (128 + 8) &&
  106.      strncmp(ptr + 128, "MThd", 4) == 0 ) {
  107.     ptr += 128;
  108.     }
  109.  
  110.     while ( strncmp(ptr, "MThd", 4) != 0 ) {
  111.     size = getdword(ptr + 4);
  112.     if ( (ptr += (8 + size)) >= btm )
  113.         goto ERROR;
  114.     }
  115.  
  116.     size = getdword(ptr + 4);
  117.     ptr += 8;
  118.     format   = getword(ptr + 0);
  119.     ntrks    = getword(ptr + 2);
  120.     division = getword(ptr + 4);
  121.     ptr += size;
  122.  
  123.     if ( ntrks <= 0 || division <= 0 )
  124.     goto ERROR;
  125.  
  126.     for ( track = 0 ; track < 32 && track < ntrks && ptr < btm ; track++ ) {
  127.     while ( strncmp(ptr, "MTrk", 4) != 0 ) {
  128.         size = getdword(ptr + 4);
  129.         if ( (ptr += (8 + size)) >= btm )
  130.         goto ERROR;
  131.     }
  132.  
  133.     size = getdword(ptr + 4);
  134.     ptr += 8;
  135.  
  136.     trtab[track].btm = ptr + size;
  137.     trtab[track].ptr = ptr + getdelta(ptr, &delta);
  138.     trtab[track].clk = delta;
  139.     trtab[track].cmd = 0x00;
  140.  
  141.     ptr += size;
  142.     }
  143.     ntrks = track;
  144.  
  145.     port = 0;
  146.     tempo = 120;
  147.     midi_clock = 0;
  148.     st = FALSE;
  149.     memset(note, 0, 16 * 128);
  150.  
  151.     EUP_open();
  152.  
  153.     SND_int_timer_a_set(MIDI_clock_count);
  154.     SND_fm_timer_a_set(0, 1024 - 17361 / tempo);
  155.     SND_fm_timer_a_start();
  156.  
  157.     while ( st == FALSE ) {
  158.     st = TRUE;
  159.     clk = midi_clock * division / 192;
  160.     for ( track = 0 ; track < ntrks ; track++ ) {
  161.         ptr = trtab[track].ptr;
  162.         while ( ptr < trtab[track].btm &&
  163.             trtab[track].clk <= clk ) {
  164.  
  165.         if ( (*ptr & 0x80) == 0 )
  166.             *(--ptr) = trtab[track].cmd;
  167.  
  168.         switch(*(ptr) & 0xF0) {
  169.         case 0x90:
  170.             trtab[track].cmd = *ptr;
  171.             ptr[1] &= 0x7F;
  172.             ptr[2] &= 0x7F;
  173.             if ( ptr[2] == 0 )
  174.             ptr[0] &= 0x8F;
  175.             else
  176.                 EUP_note_on(ptr[1] / 4, ptr[2] & 127);
  177.             SND_midi_write(port, ptr, 3);
  178.             note[ptr[0] & 0x0F][ptr[1]] = ptr[2];
  179.             ptr += 3;
  180.             break;
  181.  
  182.         case 0x80:
  183.             trtab[track].cmd = *ptr;
  184.             ptr[1] &= 0x7F;
  185.             ptr[2] &= 0x7F;
  186.             SND_midi_write(port, ptr, 3);
  187.             note[ptr[0] & 0x0F][ptr[1]] = ptr[2];
  188.             ptr += 3;
  189.             break;
  190.  
  191.         case 0xA0: case 0xB0: case 0xE0:
  192.             trtab[track].cmd = *ptr;
  193.             SND_midi_write(port, ptr, 3);
  194.             ptr += 3;
  195.             break;
  196.  
  197.         case 0xC0: case 0xD0:
  198.             trtab[track].cmd = *ptr;
  199.             SND_midi_write(port, ptr, 2);
  200.             ptr += 2;
  201.             break;
  202.  
  203.         case 0xF0:
  204.             trtab[track].cmd = 0x00;
  205.             switch(*(ptr) & 0xFF) {
  206.             case 0xF0:
  207.             ptr += 1;
  208.             SND_midi_write(port, "\xFF", 1);
  209.             ptr += getdelta(ptr, &delta);
  210.             SND_midi_write(port, ptr, delta);
  211.             ptr += delta;
  212.             break;
  213.  
  214.             case 0xF7:
  215.             ptr += 1;
  216.             ptr += getdelta(ptr, &delta);
  217.             SND_midi_write(port, ptr, delta);
  218.             ptr += delta;
  219.             break;
  220.  
  221.             case 0xF2:
  222.             ptr += 2;
  223.             break;
  224.  
  225.             case 0xF3:
  226.             ptr += 3;
  227.             break;
  228.  
  229.             case 0xF1:
  230.             case 0xF4:
  231.             case 0xF5:
  232.             case 0xF6:
  233.             case 0xF8:
  234.             case 0xFA:
  235.             case 0xFB:
  236.             case 0xFC:
  237.             case 0xFD:
  238.             case 0xFE:
  239.             ptr += 1;
  240.             break;
  241.  
  242.             case 0xFF:
  243.             switch(*(ptr + 1) & 0xFF) {
  244.             case 0x2F:        /* end of */
  245.                 ptr = trtab[track].btm;
  246.                 break;
  247.  
  248.             case 0x51:        /* tempo */
  249.                 delta = get3byte(ptr + 3);
  250.                 if ( delta > 0 ) {
  251.                 if ( (tempo = 60000000L / delta) < 30 )
  252.                     tempo = 30;
  253.                 else if ( tempo > 280 )
  254.                     tempo = 280;
  255.                 }
  256.                 SND_fm_timer_a_set(0xFF, 1024 - 17361 / tempo);
  257.                 break;
  258.             }
  259.             ptr += 2;
  260.             ptr += getdelta(ptr, &delta);
  261.             ptr += delta;
  262.             break;
  263.             }
  264.             break;
  265.  
  266.         default:
  267.             ptr++;
  268.             break;
  269.         }
  270.         ptr += getdelta(ptr, &delta);
  271.         trtab[track].clk += delta;
  272.         }
  273.         if ( (trtab[track].ptr = ptr) < trtab[track].btm )
  274.         st = FALSE;
  275.     }
  276.     EUP_chk(NULL);
  277.     MOS_rdpos(&sw, &x, &y);
  278.     if ( sw != 0 )
  279.         break;
  280.     }
  281.  
  282. ENDOF:
  283.  
  284.     SND_fm_timer_a_set(0, 1024 - 17361 / tempo);
  285.     for ( i = 0 ; i < 16 ; i++ ) {
  286.     for ( n = 0 ; n < 128 ; n++ ) {
  287.         if ( note[i][n] > 0 ) {
  288.         tmp[0] = 0x80 | i;
  289.         tmp[1] = n;
  290.         tmp[2] = 0;
  291.         SND_midi_write(port, tmp, 3);
  292.         }
  293.     }
  294.     }
  295.  
  296.     EUP_close();
  297.     free(top);
  298.     return FALSE;
  299.  
  300. ERROR:
  301.     free(top);
  302.     kakunin("対応していないMIDIファイルです");
  303.     return ERR;
  304. }
  305.